#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <graphviz/gvc.h>
#include "../include/pert.h"
#include "../include/getnum.h"


#define MAX_NAME	20

int Menu(char ** options, int optCount);
pertADT LoadFile_W(void);
int ModRed_W(pertADT pert, int mod);
int InsAct_W(pertADT pert);
int DelAct_W(pertADT pert);
void Calendar_W(pertADT pert, char ** caloptions, int totaloptions);
void Plot_W(pertADT pert);

static void  FreeMods(char ** mods, int cantMods);

int
main(void)
{
	int opt, exit = 0, subexit = 0;
	pertADT pert = NULL;
	
	char * options[5] = {"Ingresar un archivo con una tabla de actividades", 
						 "Ingresar modificaciones a una red",
						 "Obtener un calendario de actividades del proyecto para una fecha de inicio determinada",
						 "Obtener la representacion grafica de la red",
						 "Salir"};
						 
	char * suboptions[6] = {"Modificar la duracion de una actividad",
							"Modificar la descripcion de una actividad",
						 	"Modificar precedencias de una actividad",
						 	"Insertar una actividad",
						 	"Borrar una actividad",
						 	"Volver al menu anterior"};
						 
	char * caloptions[6] = {"Duracion en anios",
							"Duracion en meses",
							"Duracion en semanas",
							"Duracion en dias",
							"Duracion en horas",
							"Duracion en minutos"};
	
	/* no tocar! me costo infinito jajaja */
	
	printf("\n\n");
	printf("/|   ,ad8888ba,                                   88   				\n");                            
	printf("/|  d8\"'   `\"8b                            ,d     \"\"				\n");                            
	printf("/| d8'                                     88\n");                                   
	printf("/| 88              ,adPPYba,  ,adPPYba,  MM88MMM  88   ,adPPYba,   8b,dPPYba,   \n");   
	printf("/| 88      88888  a8P_____88  I8[    \"\"    88     88  a8\"     \"8a  88P'  ` \"8a\n");  
	printf("/| Y8,        88  8PP\"\"\"\"\"\"\"   `\"Y8ba,     88     88  8b       d8  88       88\n");  
	printf("/|  Y8a.    .a88  \"8b,   ,aa  aa    ]8I    88,    88  \"8a,   ,a8\"  88       88\n");
	printf("/|   `\"Y88888P\"    `\"Ybbd8\"'  `\"YbbdP\"'    \"Y888  88   `\"YbbdP\"'   88       88 \t\t v 1.0\n\n\n");
	
	
	/* no se verifica que opt sea -1, pues los datos enviados a Menu son correctos */
	printf("Bienvenido a Gestion v1.0, que desea hacer? \n");
	
	while(!exit)
	{
		opt = Menu((char **)options, sizeof(options)/sizeof(options[0]));
		printf("\n");
		subexit = 0;
		switch(opt)
		{
			case 1: 
						if ( (pert = LoadFile_W()) == NULL)
							printf("El archivo no existe o tiene errores, ingrese otro por favor \n\n");
						else
							printf("\n El archivo se cargo con exito \n\n");
					break;
					
			case 2: 
					while(!subexit)
					{
						opt = Menu((char **)suboptions, sizeof(suboptions)/sizeof(suboptions[0]));
						switch(opt)
						{
							case 1:
									if (!ModRed_W(pert, 0))
										fprintf(stderr, "\nLa red no fue modificada\n\n");
									break;
							case 2: 
									if (!ModRed_W(pert, 1))
										fprintf(stderr, "\nLa red no fue modificada\n\n");
									break;
							case 3:
									if (!ModRed_W(pert, 2))
										fprintf(stderr, "\nLa red no fue modificada\n\n");
									break;
							case 4:
									if (!InsAct_W(pert))
										fprintf(stderr, "\nLa actividad no fue insertada\n\n");
									break;
							case 5:
									if (!DelAct_W(pert))
										fprintf(stderr, "\nLa actividad no fue borrada\n\n");
									break;
							case 6:
									subexit = 1;
									printf("\n");
									break;		
							default:
									fprintf(stderr, "Invalid option \n");
						}
					}
					break;
					
			case 3:
					Calendar_W(pert, caloptions, sizeof(caloptions)/sizeof(caloptions[0]));
					break;
			
			case 4:
					Plot_W(pert);
					break;
					
			case 5:
					exit = 1;
					break;
			
			default: 
					fprintf(stderr, "Invalid option \n");
		}
	}
	
	if (pert != NULL)
		FreePert(pert);
	
	return 0;
}

int
Menu(char ** options, int optCount)
{
	int i, getOpt;
	
	if (options == NULL)
		return -1;
	
	for ( i = 0 ; i < optCount ; i++ )
		printf("%d - %s \n", i+1, options[i]);  

	while( (getOpt = getint("")) < 1 || getOpt > optCount )
		printf("Opcion incorrecta, por favor elija una opcion valida \n");
		
	return getOpt;
}


pertADT 
LoadFile_W(void)
{
	pertADT aux = NULL;
	char fname[MAX_NAME] = {0};
	int i = 0, c, exit = 0, attemps = 0;
	FILE * faux = NULL;
	
	
	while(i < MAX_NAME && !exit)
	{
		printf("Ingrese el nombre del archivo: \n");
		
		while ( (c = fgetc(stdin)) != '\n' && i < MAX_NAME)
			fname[i++] = c;
		
		if (i < MAX_NAME - 1)
			fname[i] = '\0';
		
		if (i == MAX_NAME)
		{	
			fprintf(stderr, "nombre del archivo excede el tamanio permitido, renombre o ingrese uno nuevo \n\n");
			attemps++;
		}
		
		else if ( (faux = fopen(fname, "rt")) == NULL)	
		{	
			fprintf(stderr, "no se pudo abrir el archivo, el archivo no existe o esta corrupto \n\n");
			attemps++;
		}
		
		else
			exit = 1;
				
		if (attemps == 5)
		{
			fprintf(stderr, "Numero de intentos excedido \n");
			exit = 1;
		}
		
		i = 0;
	}
	
	if (faux != NULL)
	{
			aux = LoadPert(faux);
			fclose(faux);
	}
	
	return aux;
}

int 
ModRed_W(pertADT pert, int mod)
{
	char ** changes;
	char * msg[3] = {"Ingrese la nueva duracion de la actividad",
					 "Ingrese la nueva descripcion a asignarle a la actividad",
					 "Ingrese la unica nueva precedencia, o un \"-\" si no las tiene, de la actividad"}; 
	char act[20] = {0};
	char newInfo[100] = {0};
	int i = 1, ok;
	char c;
	
	if (pert == NULL)
	{
		fprintf(stderr, "\nNo hay red cargada\n");
		return 0;
	}
	
	if ( (changes = calloc(4, sizeof(char *))) == NULL )
		return 0;
		
	printf("Ingrese el ID de la actividad a modificar: ");
	scanf("%s", act);
	
	if ( (changes[0] = malloc((strlen(act) + 1) * sizeof(char))) == NULL)
	{
		fprintf(stderr, "Memoria insuficiente para realizar la modificacion\n");
		free(changes);
		return 0;
	}
	
	strcpy(changes[0], act);
	
	for (i = 1 ; i < 4 ; i++)
		if (i != mod+1)
			changes[i] = NULL;
	
	while( (c = getchar()) != '\n');
	
	printf("\n%s %s: ", msg[mod], act);
	
	if ((mod+1) != 2)
		scanf("%s", newInfo);
	else
	{
		i = 0;
		while( (c = getchar()) != '\n' && c != EOF)
			newInfo[i++] = c;
			
		newInfo[i] = '\0';
	}
	
	if ( (changes[mod+1] = malloc((strlen(newInfo) + 1) * sizeof(char))) == NULL )
	{
		fprintf(stderr, "Memoria insuficiente para realizar la modificacion\n");
		FreeMods(changes, 4);
		return 0;
	}
			
	
	strcpy(changes[mod+1], newInfo);
	
	ok = ModifyTask(pert, mod+1, changes);
	
	FreeMods(changes, 4);
		
	return ok;
}

static void 
FreeMods(char ** mods, int cantMods)
{
	int i;
	
	for (i = 0 ; i < cantMods ; i++)
		if (mods[i] != NULL)
			free(mods[i]);
			
	free(mods);
	return;
}

int
InsAct_W(pertADT pert)
{
	char * info, * delims = ";\n";
	char ** changes;
	char * token, * aux;
	int i = 0, ok;
	
	if (pert == NULL)
	{
		fprintf(stderr, "\nNo hay red cargada\n");
		return 0;
	}
	
	if ( (changes = calloc(4, sizeof(char *))) == NULL )
		return 0;
		
	if ( (info = calloc(101, sizeof(char))) == NULL)
	{
		free(changes);
		return 0;
	}
	
	/* Pide la actividad a ingresar */
	
	printf("Ingrese los datos de la nueva actividad a Insertar con formato \"ID;Descripcion;Duracion;Prec;Suc\n");
	printf("Atencion: Solo se puede ingresar una unica precedencia y un unico sucesor\n");
	
	info = fgets(info, 100, stdin);
	
	if ( (token = strtok(info, delims)) == NULL)
	{
		free(info);
		free(changes);
		return 0;
	}
	
	do
	{
		if ( (changes[i] = malloc((strlen(info) + 1) * sizeof(char))) == NULL )
		{
			free(info);
			FreeMods(changes, 5);
			return 0;
		}
		
		strcpy(changes[i++], token);
		
		if ( (aux = strchr(changes[i-1], 10)) != NULL)
			*aux = '\0';
			
	}
	while( (token = strtok(NULL, delims)) != NULL);
	
	if (i!= 5)
	{
		FreeMods(changes, 5);
		free(info);
		return 0;
	}
	
	ok = InsertTask(pert, changes);
	
	FreeMods(changes, 5);
	free(info);
	
	return ok;
}




int
DelAct_W(pertADT pert)
{
	char aux[20] = {0};
	char * act;
	int ok;
	
	if (pert == NULL)
	{
		fprintf(stderr, "\nNo hay red cargada\n");
		return 0;
	}
	
	/* Pide la actividad a ingresar */
	
	printf("Ingrese el ID de la actividad a Borrar: ");
	scanf("%s", aux);
	
	if ( (act = malloc((strlen(aux) + 1) * sizeof(char))) == NULL )
	{
		fprintf(stderr, "\nMemoria insuficiente para Borrar Actividad\n");
		return 0;
	}
	
	strcpy(act, aux);
	
	ok = DeleteTask(pert, act);
	free(act);
	return ok;
}


void 
Calendar_W(pertADT pert, char ** caloptions, int totaloptions)
{
	int opt, frmopt, frmLength, exit = 0;
	char * Format[2] = {"dd/mm/yyyy", "dd/mm/yyyy hh:mm"}; 
	TimeUnit unit;
	/* Se pide la unidad de tiempo al usuario y en base a eso, se elije el formato para
	 * imprimir el calendario
	 */
	
	if (pert == NULL)
	{
		fprintf(stderr, "\nAun no se ha cargado ningun archivo de proyecto \n\n");
		return;
	}
	 
	printf("\n Elija la unidad de tiempo de duracion de las tareas \n\n");
	 
	while(!exit)
	{
		opt = Menu(caloptions, totaloptions);
		printf("\n");
		
		switch(opt)
		{
			case 1: 
					unit = ANIO;
					frmopt = 0;
					exit = 1;
					break;
					
			case 2: 
					unit = MES;
					frmopt = 0;
					exit = 1;
					break;
			case 3: 
					unit = SEM;
					frmopt = 0;
					exit = 1;
					break;		
			case 4: 
					unit = DIA;
					frmopt = 0;
					exit = 1;
					break;
					
			case 5: 
					unit = HORA;
					frmopt = 1;
					exit = 1;
					break;
			case 6: 
					unit = MINUTO;
					frmopt = 1;
					exit = 1;
					break;
					
			default: 
					fprintf(stderr, "opcion invalida \n");
					break;
		}
	}
	
	frmLength = strlen(Format[frmopt]) + 1;
	
	if (!Calendar(pert, frmLength, unit))
	{
		fprintf(stderr, "\nNo se pudo generars el calendario \n");
		return;
	}
	
	printf("\nCalendario salvado en el archivo calendar.txt \n\n");
	
	return;
}

void 
Plot_W(pertADT pert)
{
	FILE * gaux;
	GVC_t *context;
	graph_t *graph;
	FILE *fp;
	FILE * pertgraph;
	
	if (pert == NULL)
	{	
		fprintf(stderr, "No hay red cargada \n");
		return;
	}
	
	if ( (gaux = CreateDotFile(pert)) == NULL)
	{
		fprintf(stderr, "Error al intentar de graficar \n");
		return;
	}

	pertgraph = fopen("graph.png", "w+t");
	
	context = gvContext();
	fp = fopen("graph.dot", "r");
	graph = agread(fp); /* Compila gráfico */
	gvLayout(context, graph, "dot"); /* Crear capa con el algoritmo de dot */
	gvRender(context, graph, "gif", pertgraph); /* Muestra gráfico en pantalla en formato PNG */
	
	gvFreeLayout(context, graph);
	agclose(graph);
	gvFreeContext(context);
	fclose(fp);
	fclose(pertgraph);
	printf("\nRepresentacion grafica se encuentra en el archivo graph.png \n\n");
	return;
}
